package com.cloudkinto.service.order.returns.impl;

import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.hutool.core.collection.ListUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cloudkinto.common.BeanConvert;
import com.cloudkinto.common.RedisKeyConstants;
import com.cloudkinto.common.common.DateUtils;
import com.cloudkinto.common.constant.SysConstant;
import com.cloudkinto.common.exception.BizException;
import com.cloudkinto.common.utils.ExcelUtils;
import com.cloudkinto.common.utils.TimeUtils;
import com.cloudkinto.common.utils.ali.AliOss;
import com.cloudkinto.common.utils.dict.StaticDict;
import com.cloudkinto.common.web.PageResult;
import com.cloudkinto.common.web.SingleResult;
import com.cloudkinto.dao.*;
import com.cloudkinto.dto.order.returns.OrderReturnPageDto;
import com.cloudkinto.dto.order.returns.pack.OrPackDetailDto;
import com.cloudkinto.dto.order.returns.pack.PackTrackDto;
import com.cloudkinto.dto.order.returns.product.OrProductPageDto;
import com.cloudkinto.dto.order.returns.product.ProductQtyDto;
import com.cloudkinto.entity.*;
import com.cloudkinto.enumType.operate.OperateTypeEnum;
import com.cloudkinto.enumType.stock.StockOrderTypeEnum;
import com.cloudkinto.enumType.stock.StockTypeEnum;
import com.cloudkinto.enumType.storage.StorageAreaEnum;
import com.cloudkinto.service.company.CompanyService;
import com.cloudkinto.service.file.FileMoreService;
import com.cloudkinto.service.file.FileService;
import com.cloudkinto.service.operate.OperateRecordService;
import com.cloudkinto.service.order.returns.OrderReturnPackService;
import com.cloudkinto.service.order.returns.OrderReturnService;
import com.cloudkinto.service.stock.ProductStockFlowingService;
import com.cloudkinto.service.stock.ProductStockService;
import com.cloudkinto.service.storage.impl.StorageLocationServiceImpl;
import com.cloudkinto.service.warehouse.WarehouseService;
import com.cloudkinto.service.wr.QuotationSchemeService;
import com.cloudkinto.utils.BarCodePdfUtils;
import com.cloudkinto.utils.BeanCopierUtils;
import com.cloudkinto.vo.cost.CostAddEt;
import com.cloudkinto.vo.file.FileMsg;
import com.cloudkinto.vo.file.FileRes;
import com.cloudkinto.vo.order.returns.*;
import com.cloudkinto.vo.order.returns.importVo.OrderReturnErrorExportVo;
import com.cloudkinto.vo.order.returns.importVo.OrderReturnImportRes;
import com.cloudkinto.vo.order.returns.importVo.OrderReturnImportVo;
import com.cloudkinto.vo.order.returns.importVo.OrderReturnWmsExportVo;
import com.cloudkinto.vo.order.returns.pack.OrPackAddReq;
import com.cloudkinto.vo.order.returns.pack.OrPackDetailRes;
import com.cloudkinto.vo.order.returns.pack.OrPackUpdateReq;
import com.cloudkinto.vo.order.returns.pack.OrWmsPackScanReq;
import com.cloudkinto.vo.order.returns.print.PrintReq;
import com.cloudkinto.vo.order.returns.print.PrintSkuEt;
import com.cloudkinto.vo.order.returns.product.OrProductAddReq;
import com.cloudkinto.vo.order.returns.product.OrProductUpdateReq;
import com.cloudkinto.vo.order.returns.product.OrWmsProductScanReq;
import com.cloudkinto.vo.sc.style.FarawayExportTitleStyle;
import com.cloudkinto.vo.stock.ProductFlowingInEt;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * service实现类
 * </p>
 *
 * @author hua
 * @since 2024-11-19
 */
@Service
@Transactional(rollbackFor = Exception.class)//事务回滚
public class OrderReturnServiceImpl extends ServiceImpl<OrderReturnDao, OrderReturnDo> implements OrderReturnService {
    @Autowired
    private OrderReturnDao dao;
    @Autowired
    private OrderReturnProductDao orderReturnProductDao;
    @Autowired
    private OrderReturnPackDao orderReturnPackDao;
    @Autowired
    private OrderReturnPackService orderReturnPackService;
    @Autowired
    private FileService fileService;
    @Autowired
    private FileMoreService fileMoreService;
    @Autowired
    private OperateRecordService operateRecordService;
    @Autowired
    private CompanyDao companyDao;
    @Autowired
    private ProductStockDao productStockDao;
    @Autowired
    private ProductStockService productStockService;
    @Autowired
    private ProductStockRackDao productStockRackDao;
    @Autowired
    private CompanyService companyService;
    @Autowired
    private WarehouseService warehouseService;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private StorageLocationDao storageLocationDao;
    @Autowired
    private ProductDao productDao;
    @Value("${gbc.uploadPath.filePathTemp}")
    private String filePathTemp;
    @Value("${gbc.uploadPath.filePath}")
    private String filePath;
    @Value("${gbc.uploadPath.fileUrl}")
    private String fileUrl;
    @Autowired
    private ProductStockFlowingService productStockFlowingService;
    @Autowired
    private QuotationSchemeService quotationSchemeService;


    @Override
    public SingleResult addInit() {
        return SingleResult.success("");
    }

    public Long add(OrderReturnAddReq req, Long userId, Long companyId) {
        OrderReturnDo o = this.addReturn(req, userId, companyId);
        if (o == null) {
            return null;
        }
        return o.getId();
    }

    @Override
    public OrderReturnDo addReturn(OrderReturnAddReq req, Long userId, Long companyId) {
        if (companyId == null) return null;
        OrderReturnDo entityDo = new OrderReturnDo();
        BeanUtils.copyProperties(req, entityDo);
        entityDo.setStatus(req.getPush());
        entityDo.setCompanyId(companyId);
        if (StaticDict.Order_Return_Status.One.getValue().equals(entityDo.getStatus())) {
            entityDo.setSubmitBy(userId);
            entityDo.setSubmitTime(new Date());
        }
        dao.insert(entityDo);
        StringBuilder returnNo = new StringBuilder(entityDo.getId() + "");
        while (returnNo.length() < 4) {
            returnNo.insert(0, 0);
        }
        CompanyDo companyDo = companyDao.selectById(companyId);
        returnNo.insert(0, DateUtils.dateFormatToString(new Date(), "yyMMdd")).insert(0, companyDo.getCompanyCode()).insert(0, "RI");
        entityDo.setReturnNo(returnNo.toString());
        dao.updateById(entityDo);

        for (OrPackAddReq pack : req.getPacks()) {
            OrderReturnPackDo packDo = new OrderReturnPackDo();
            BeanUtils.copyProperties(pack, packDo);
            packDo.setReturnId(entityDo.getId());
            //附件
            if (pack.getFile() != null && pack.getFile().getFileId() != null) {
                fileService.uploadFile(pack.getFile().getFileId());
                packDo.setFileId(pack.getFile().getFileId());
            }
            orderReturnPackDao.insert(packDo);

        }
        for (OrProductAddReq product : req.getProducts()) {
            OrderReturnProductDo productDo = new OrderReturnProductDo();
            BeanUtils.copyProperties(product, productDo);
            productDo.setReturnId(entityDo.getId());
            //附件
            if (product.getFile() != null && product.getFile().getFileId() != null) {
                fileService.uploadFile(product.getFile().getFileId());
                productDo.setFileId(product.getFile().getFileId());
            }
            orderReturnProductDao.insert(productDo);
        }

        if (req.getFiles() != null) {
            //主表附件
            List<Long> fileIds = req.getFiles().stream().map(FileMsg::getFileId).filter(Objects::nonNull).collect(Collectors.toList());
            fileMoreService.insertFileMoreList(fileIds, entityDo.getId(), StaticDict.File_Type.OrderReturn_Cus.getValue(), userId, null);
        }
        operateRecordService.operateAddRecordAndValue("新建退件单", "", entityDo.getId(), userId, null, OperateTypeEnum.OrderReturn);

        return entityDo;
    }


    @Override
    public SingleResult updateInit(Long id) {
        return SingleResult.success("");
    }

    @Override
    public Object update(OrderReturnUpdateReq req, Long userId, Long loginId, String source) {
        OrderReturnDo entityDo = this.lambdaQuery().eq(OrderReturnDo::getId, req.getId())
                .eq("oms".equals(source), OrderReturnDo::getCompanyId, loginId)
                .eq("wms".equals(source), OrderReturnDo::getTenantId, loginId).one();
        if (entityDo == null) throw new BizException(SysConstant.No_Data);
        if (entityDo.getStatus() > StaticDict.Order_Return_Status.Zero.getValue()) return entityDo.getId();
        BeanUtils.copyProperties(req, entityDo);
        entityDo.setStatus(req.getPush());
        dao.updateById(entityDo);
        //包裹
        List<OrPackDetailDto> trackDetailList = orderReturnPackDao.getTrackDetail(Collections.singletonList(entityDo.getId()));
        List<Long> oldFileIds = trackDetailList.stream().map(OrPackDetailDto::getFileId).filter(Objects::nonNull).collect(Collectors.toList());
        List<Long> oldPackIds = trackDetailList.stream().map(OrPackDetailDto::getId).collect(Collectors.toList());
        List<Long> newWPackIds = req.getPacks().stream().map(OrPackUpdateReq::getId).filter(Objects::nonNull).collect(Collectors.toList());
        //找出要删除的
        List<Long> deletePackIds = oldPackIds.stream().filter(i -> !newWPackIds.contains(i)).collect(Collectors.toList());
        if (!deletePackIds.isEmpty()) orderReturnPackDao.updateD(deletePackIds, userId);
        for (OrPackUpdateReq pack : req.getPacks()) {
//            if (pack.getId() != null && !pack.isEdit()) continue;
            OrderReturnPackDo packDo = new OrderReturnPackDo();
            BeanUtils.copyProperties(pack, packDo);
            packDo.setReturnId(entityDo.getId());
            if (pack.getFile() != null && pack.getFile().getFileId() != null && !oldFileIds.contains(pack.getFile().getFileId())) {
                fileService.uploadFile(pack.getFile().getFileId());
                packDo.setFileId(pack.getFile().getFileId());
            }
            if (pack.getId() == null) orderReturnPackDao.insert(packDo);
            else orderReturnPackDao.updateById(packDo);
        }
        //产品
        List<OrProductPageDto> productPageList = orderReturnProductDao.list(Collections.singletonList(entityDo.getId()));
        List<Long> newProductIds = req.getProducts().stream().map(OrProductUpdateReq::getId).filter(Objects::nonNull).collect(Collectors.toList());
        List<Long> oldProductIds = productPageList.stream().map(OrProductPageDto::getId).collect(Collectors.toList());
        List<Long> deleteProductIds = oldProductIds.stream().filter(i -> !newProductIds.contains(i)).collect(Collectors.toList());
        if (!deleteProductIds.isEmpty()) orderReturnProductDao.updateD(deleteProductIds, userId);
        for (OrProductUpdateReq product : req.getProducts()) {
//            if (product.getId() != null && !product.isEdit()) continue;
            OrderReturnProductDo productDo = new OrderReturnProductDo();
            BeanUtils.copyProperties(product, productDo);
            productDo.setReturnId(entityDo.getId());
            if (product.getFile() != null && product.getFile().getFileId() != null && !oldFileIds.contains(product.getFile().getFileId())) {
                fileService.uploadFile(product.getFile().getFileId());
                productDo.setFileId(product.getFile().getFileId());
            }
            if (product.getId() == null) orderReturnProductDao.insert(productDo);
            else orderReturnProductDao.updateById(productDo);
        }
//        List<Long> fileIds = req.getFiles().stream().map(FileMsg::getFileId).filter(Objects::nonNull).collect(Collectors.toList());
//        fileMoreService.insertFileMoreList(null, entityDo.getId(), StaticDict.File_Type.OrderReturn_Cus.getValue(), userId, null);
        return null;
    }


    @Override
    public int delete(Long id, Long userId) {
        OrderReturnDo entityDo = dao.selectById(id);
        return dao.deleteById(id);
    }


    @Override
    public OrDetailRes detail(Long id, Long loginId, String source) {
        Map<String, Object> map = new HashMap<>();
        map.put("id", id);
        if ("oms".equals(source)) {
            map.put("companyId", loginId);
        } else if ("wms".equals(source)) {
            map.put("tenantId", loginId);
        } else {
            return null;
        }
        String remark=dao.getRemark(id);
        String salesPlatForm=dao.getSalesPlatform(id);


        List<OrderReturnPageDto> eList = dao.list(map);
        if (eList.isEmpty()) throw new BizException(SysConstant.No_Data);
        OrderReturnPageDto et = eList.get(0);
        OrDetailRes res = new OrDetailRes();
        BeanUtils.copyProperties(et, res);
        res.setPacks(this.getPackDetail(id, et.getSizeUnit(), et.getWmsSizeUnit()));
        //退货产品
        List<OrProductPageDto> productPageList = orderReturnProductDao.list(Collections.singletonList(et.getId()));
        List<OrProductDetailRes> products = BeanCopierUtils.listCopyMapper(productPageList, OrProductPageDto.class, OrProductDetailRes.class);
        for (OrProductDetailRes product : products) {
            if (product.getFileId() == null) continue;
            //获取附件信息
            product.setFile(fileService.getFileMsg(product.getFileId()));
        }
        res.setProducts(products);
        res.setRacks(productStockService.getReturnStockRecord(et.getId()));
        //附件
        List<FileRes> fileList = fileMoreService.getFileList(id, StaticDict.File_Type.OrderReturn_Cus.getValue());
        res.setOmsFiles(fileList);
        res.setWmsFiles(fileMoreService.getFileList(id, StaticDict.File_Type.OrderReturn_Ware.getValue()));
        //进度条
        this.setProgressList(res);

        List<PackTrackDto> tracks = orderReturnPackDao.getTracks(Collections.singletonList(id));
        res.setTrackList(tracks);

        res.setOperateResList(operateRecordService.getOperateList(id, OperateTypeEnum.OrderReturn));

        res.setRemark(remark);
        res.setSalesPlatForm(salesPlatForm);
        return res;
    }


    @Override
    public List<OrPackDetailRes> getPackDetail(Long id, String sizeUnit, String wmsUnit) {
        //退件包裹
        List<OrPackDetailDto> trackDetailList = orderReturnPackDao.getTrackDetail(Collections.singletonList(id));

        List<OrPackDetailRes> packDetailList = BeanCopierUtils.listCopyMapper(trackDetailList, OrPackDetailDto.class, OrPackDetailRes.class);
        for (OrPackDetailRes pack : packDetailList) {
            //附件
            pack.setFile(fileService.getFileMsg(pack.getFileId()));
            //cm -> in 0.3937008  in -> cm 2.5399999
            if (StaticDict.OMP_UnitMeasurement.Cm.getValue().equals(sizeUnit)) {
                //公制
                if (pack.getLength() != null) {
                    pack.setLengthBs(pack.getLength() * StaticDict.OMP_Unit.Cm.getCoe());
                }
                if (pack.getWidth() != null) {
                    pack.setWidthBs(pack.getWidth() * StaticDict.OMP_Unit.Cm.getCoe());
                }
                if (pack.getHeight() != null) {
                    pack.setHeightBs(pack.getHeight() * StaticDict.OMP_Unit.Cm.getCoe());
                }
                if (pack.getWeight() != null) {
                    pack.setWeightBs(pack.getWeight() * StaticDict.OMP_Unit.Kg.getCoe());
                }
            } else {
                //英制
                pack.setLengthBs(pack.getLength());
                pack.setWidthBs(pack.getWidth());
                pack.setHeightBs(pack.getHeight());
                pack.setWeightBs(pack.getWeight());
                if (pack.getLengthBs() != null) {
                    pack.setLength(pack.getLengthBs() * StaticDict.OMP_Unit.In.getCoe());
                }
                if (pack.getWidthBs() != null) {
                    pack.setWidth(pack.getWidthBs() * StaticDict.OMP_Unit.In.getCoe());
                }
                if (pack.getHeightBs() != null) {
                    pack.setHeight(pack.getHeightBs() * StaticDict.OMP_Unit.In.getCoe());
                }
                if (pack.getWeightBs() != null) {
                    pack.setWeight(pack.getWeightBs() * StaticDict.OMP_Unit.Lb.getCoe());
                }
            }
            //wms
            if (pack.getLengthW() != null) {
                //说明录入了wms尺寸
                if (StaticDict.OMP_UnitMeasurement.Cm.getValue().equals(wmsUnit)) {
                    //公制
                    pack.setLengthW_bs(pack.getLengthW() * StaticDict.OMP_Unit.Cm.getCoe());
                    pack.setWidthW_bs(pack.getWidthW() == null ? 0d : pack.getWeightW() * StaticDict.OMP_Unit.Cm.getCoe());
                    pack.setHeightW_bs(pack.getHeightW() == null ? 0d : pack.getHeightW()* StaticDict.OMP_Unit.Cm.getCoe());
                    pack.setWeightW_bs(pack.getWeightW() == null ? 0d : pack.getWeightW()* StaticDict.OMP_Unit.Kg.getCoe());
                } else {
                    //英制
                    pack.setLengthW_bs(pack.getLengthW());
                    pack.setWidthW_bs(pack.getWidthW());
                    pack.setHeightW_bs(pack.getHeightW());
                    pack.setWeightW_bs(pack.getWeightW());

                    pack.setLengthW(pack.getLengthW_bs() == null ? 0d : pack.getLengthW_bs() * StaticDict.OMP_Unit.In.getCoe());
                    pack.setWidthW(pack.getWidthW_bs()  == null ? 0d : pack.getWidthW_bs()* StaticDict.OMP_Unit.In.getCoe());
                    pack.setHeightW(pack.getHeightW_bs() == null ? 0d : pack.getHeightW_bs() * StaticDict.OMP_Unit.In.getCoe());
                    pack.setWeightW(pack.getWeightW_bs() == null ? 0d : pack.getWeightW_bs()* StaticDict.OMP_Unit.Lb.getCoe());
                }
            }
        }
        return packDetailList;
    }

    public void setProgressList(OrDetailRes res) {
        List<OrProgressRes> progressList = new ArrayList<>();
        progressList.add(new OrProgressRes("create", "创建", res.getReturnNo(), res.getCreateTime(), res.getCreateByName()));
        progressList.add(new OrProgressRes("submit", "提交", res.getReturnNo(), res.getSubmitTime(), res.getSubmitByName()));
        if (!StaticDict.Order_Return_Status.Four.getValue().equals(res.getStatus()) || res.getSignTime() != null) {
            progressList.add(new OrProgressRes("sign", "开始处理", res.getReturnNo(), res.getSignTime(), res.getSignByName()));
        }
        if (res.getCheckStatus() == 1) {
            progressList.add(new OrProgressRes("inventoried", "清点完成", res.getReturnNo(), res.getInventoriedTime(), res.getInventoriedByName()));
        } else {
            if (!StaticDict.Order_Return_Status.Four.getValue().equals(res.getStatus())) {
                progressList.add(new OrProgressRes("inventoried", "清点完成", res.getReturnNo(), null, null));
            }
        }
        if (res.getPutStatus() == 1 && res.getInventoriedTime() != null && res.getCheckStatus() == 1) {//只有清点了 才能上架,只有清点完成且 不可上架 才算处理完成
            progressList.add(new OrProgressRes("putaway", "处理完成", res.getReturnNo(), res.getPutawayTime(), res.getPutawayByName()));
        } else {
            if (!StaticDict.Order_Return_Status.Four.getValue().equals(res.getStatus())) {
                progressList.add(new OrProgressRes("putaway", "处理完成", res.getReturnNo(), null, null));
            }
        }
        if (StaticDict.Order_Return_Status.Four.getValue().equals(res.getStatus())) {
            progressList.add(new OrProgressRes("cancel", "取消", res.getReturnNo(), res.getCancelTime(), res.getCancelByName()));
        }
        res.setProgress(progressList);
    }


    @Override
    public SingleResult pageInit(Long userId, Long companyId, Long tenantId, String source) {
        Map<String, Object> result = new HashMap<>();
        List<Map<Object, Object>> orderReturnStatus = StaticDict.getOrder_Return_Status();
        Map<Object, Object> map = new HashMap<>();
        map.put("id", null);
        map.put("name", "全部");
        orderReturnStatus.add(0, map);
        result.put("returnStatus", orderReturnStatus);
        //wms 登录 需要客户列表
        if ("wms".equals(source)) {
            //库区类型
            result.put("storageAreaType", StorageAreaEnum.getMapList());
            //库位类型
            result.put("storageLocationType", StorageLocationServiceImpl.storageLocationTypeMap);
            result.put("companyList", companyService.getCompanyList(userId, tenantId, source));
        }
        //oms登录 需要仓库
        if ("oms".equals(source)) result.put("warehouseList", warehouseService.getWarehouseCompany(companyId, tenantId));

        return SingleResult.success(result);
    }

    @Override
    public List<OrderReturnPageDto> getList(Map<String, Object> map) {
        return dao.list(map);
    }

    @Override
    public PageResult getListPage(Map<String, Object> map) {
        IPage<OrderReturnPageDto> page = pageInit(map);
        page = dao.list(page, map);
        //   获取已收/总产品数量
        List<Long> ids = page.getRecords().stream().map(OrderReturnPageDto::getId).collect(Collectors.toList());
        if (!ids.isEmpty()) {
            Map<Long, List<OrProductPageDto>> collect = orderReturnProductDao.list(ids).stream().collect(Collectors.groupingBy(OrProductPageDto::getReturnId));
            //获取物流追踪号
            Map<Long, List<PackTrackDto>> trackC = orderReturnPackDao.getTracks(ids).stream().collect(Collectors.groupingBy(PackTrackDto::getReturnId));
            for (OrderReturnPageDto record : page.getRecords()) {
                if (collect.get(record.getId()) != null) {
                    List<OrProductPageDto> products = collect.get(record.getId());
                    record.setProducts(products);
                    record.setDeliveryQty(products.stream().mapToInt(OrProductPageDto::getDeliveryQty).sum());
                    record.setReceiveQty(products.stream().mapToInt(OrProductPageDto::getReceiveQty).sum());
                }
                record.setTrackList(trackC.get(record.getId()));
            }
        }

        PageResult result = new PageResult(page.getRecords(), (int) page.getCurrent(), (int) page.getSize(), (int) page.getTotal(), (int) page.getPages());
        return result;
    }

    @Override
    public List<Map<String, Object>> statusStatistics(Map<String, Object> map) {
        map.remove("status");
        Map<Integer, List<OrderReturnPageDto>> collect = dao.list(map).stream().collect(Collectors.groupingBy(OrderReturnPageDto::getStatus));
        List<Map<String, Object>> resultList = new ArrayList<>();
        for (StaticDict.Order_Return_Status value : StaticDict.Order_Return_Status.values()) {
            Map<String, Object> m = new HashMap<>();
            m.put("id", value.getValue());
            m.put("name", value.getText());
            m.put("sum", collect.get(value.getValue()) == null ? 0 : collect.get(value.getValue()).size());
            resultList.add(m);
        }
        return resultList;
    }


    private IPage<OrderReturnPageDto> pageInit(Map<String, Object> map) {
        IPage<OrderReturnPageDto> page = new Page<>();
        page.setSize(map.get("pageSize") != null ? Long.parseLong(map.get("pageSize").toString()) : 10);
        page.setCurrent(map.get("current") != null ? Long.parseLong(map.get("current").toString()) : 1);
        return page;
    }

    @Override
    public void submit(OrUtilReq req, Long userId, Long companyId) {
        if (req.getId() == null || req.getId().isEmpty()) return;
        List<OrderReturnDo> list = this.lambdaQuery().in(OrderReturnDo::getId, req.getId())
                .eq(OrderReturnDo::getCompanyId, companyId).list();
        for (OrderReturnDo et : list) {
            if (!StaticDict.Order_Return_Status.Zero.getValue().equals(et.getStatus())) continue;
            et.setStatus(StaticDict.Order_Return_Status.One.getValue());
            et.setSubmitBy(userId);
            et.setSubmitTime(new Date());
            dao.updateById(et);
            operateRecordService.operateAddRecordAndValue("提交退件单", "", et.getId(), userId, null, OperateTypeEnum.OrderReturn);
        }
    }


    @Override
    public void cancel(OrUtilReq req, Long userId, Long companyId) {
        if (req.getId() == null || req.getId().isEmpty()) return;
        List<OrderReturnDo> list = this.lambdaQuery().in(OrderReturnDo::getId, req.getId())
                .eq(OrderReturnDo::getCompanyId, companyId).list();
        for (OrderReturnDo et : list) {
            if (!StaticDict.Order_Return_Status.Zero.getValue().equals(et.getStatus()) && !StaticDict.Order_Return_Status.One.getValue().equals(et.getStatus()))
                continue;
            et.setStatus(StaticDict.Order_Return_Status.Four.getValue());
            et.setCancelBy(userId);
            et.setCancelTime(new Date());
            dao.updateById(et);
            operateRecordService.operateAddRecordAndValue("取消退件单", "", et.getId(), userId, null, OperateTypeEnum.OrderReturn);
        }
    }

    /**
     * 获取包裹列表 for 添加包裹
     *
     * @param id
     * @return
     */
    @Override
    public OrDetailRes packageList(Long id) {
        Map<String, Object> map = new HashMap<>();
        map.put("id", id);
        List<OrderReturnPageDto> eList = dao.list(map);
        if (eList.isEmpty()) throw new BizException(SysConstant.No_Data);
        OrderReturnPageDto et = eList.get(0);
        OrDetailRes res = new OrDetailRes();
        BeanUtils.copyProperties(et, res);
        res.setPacks(this.getPackDetail(id, et.getSizeUnit(), et.getWmsSizeUnit()));
        return res;
    }

    @Override
    public void updatePackage(OrderReturnPUpdateReq req, Long userId) {
        OrderReturnDo et = dao.selectById(req.getId());
        if (et == null || StaticDict.Order_Return_Status.Four.getValue().equals(et.getStatus()) || StaticDict.Order_Return_Status.Three.getValue().equals(et.getStatus()))
            return;
        if (!et.getSizeUnit().equals(req.getSizeUnit())) {
            et.setSizeUnit(req.getSizeUnit());
            dao.updateById(et);
            List<OrderReturnPackDo> list = orderReturnPackService.list(new LambdaQueryWrapper<OrderReturnPackDo>().eq(OrderReturnPackDo::getReturnId, et.getId()));
            for (OrderReturnPackDo packDo : list) {
                if (StaticDict.OMP_UnitMeasurement.Cm.getValue().equals(req.getSizeUnit())) {
                    //英制转公制
                    packDo.setLength(packDo.getLength() * StaticDict.OMP_Unit.In.getCoe());
                    packDo.setWidth(packDo.getWidth() * StaticDict.OMP_Unit.In.getCoe());
                    packDo.setHeight(packDo.getHeight() * StaticDict.OMP_Unit.In.getCoe());
                    packDo.setWeight(packDo.getWeight() * StaticDict.OMP_Unit.In.getCoe());
                }
                else {
                    packDo.setLength(packDo.getLength() * StaticDict.OMP_Unit.Cm.getCoe());
                    packDo.setWidth(packDo.getWidth() * StaticDict.OMP_Unit.Cm.getCoe());
                    packDo.setHeight(packDo.getHeight() * StaticDict.OMP_Unit.Cm.getCoe());
                    packDo.setWeight(packDo.getWeight() * StaticDict.OMP_Unit.Cm.getCoe());
                }
                orderReturnPackService.updateById(packDo);
            }
        }
        for (OrPackUpdateReq pack : req.getPacks()) {
            if (pack.getId() != null) continue;
            OrderReturnPackDo packDo = new OrderReturnPackDo();
            BeanUtils.copyProperties(pack, packDo);
            packDo.setReturnId(et.getId());
            //附件
            if (pack.getFile() != null && pack.getFile().getFileId() != null) {
                fileService.uploadFile(pack.getFile().getFileId());
                packDo.setFileId(pack.getFile().getFileId());
            }
            orderReturnPackDao.insert(packDo);
        }

        operateRecordService.operateAddRecordAndValue("添加包裹", "", et.getId(), userId, null, OperateTypeEnum.OrderReturn);

    }


    @Override
    public void updateExpectedDate(UpdateExpectedDateReq req, Long userId) {
        if (req.getId() == null) return;
        if (req.getExpectedDate() == null) return;
        for (Long returnId : req.getId()) {
            OrderReturnDo et = dao.selectById(returnId);
            if (et == null) continue;
            if (!StaticDict.Order_Return_Status.Zero.getValue().equals(et.getStatus()) && !StaticDict.Order_Return_Status.One.getValue().equals(et.getStatus()))
                continue;
            et.setExpectedDate(req.getExpectedDate());
            dao.updateById(et);

            operateRecordService.operateAddRecordAndValue("更新预计到达时间", "", et.getId(), userId, null, OperateTypeEnum.OrderReturn);
        }
    }

    /**
     * WMS清点
     *
     * @param req
     * @param userId
     */
    @Override
    public void confirmInventory(OrWmsScanReq req, Long userId, Long tenantId) {
        if (req.getId() == null) {
            OrderReturnAddReq addReq = new OrderReturnAddReq();
            addReq.setWarehouseId(req.getWarehouseId());
            addReq.setReturnType(3);//服务商退件
            addReq.setPush(1);
            addReq.setSizeUnit(req.getWmsSizeUnit());
            addReq.setWmsSizeUnit(req.getWmsSizeUnit());
            addReq.setWarehouseRemark(req.getWarehouseRemark());
            List<OrPackAddReq> packEts = new ArrayList<>();
            //pack
            for (OrWmsPackScanReq pack : req.getPacks()) {
                OrPackAddReq packAddReq = new OrPackAddReq();
                BeanUtils.copyProperties(pack, packAddReq);
                packAddReq.setLength(pack.getLengthW());
                packAddReq.setWidth(pack.getWidthW());
                packAddReq.setHeight(pack.getHeightW());
                packAddReq.setWeight(pack.getWeightW());
                packEts.add(packAddReq);

            }
            addReq.setPacks(packEts);
            List<OrProductAddReq> products = new ArrayList<>();
            //product
            for (OrWmsProductScanReq product : req.getProducts()) {
                OrProductAddReq productAddReq = new OrProductAddReq();
                BeanUtils.copyProperties(product, productAddReq);
                products.add(productAddReq);
            }
            addReq.setProducts(products);
            Long add = this.add(addReq, userId, req.getCompanyId());
            req.setId(add);
        }

        OrderReturnDo et = dao.selectById(req.getId());
        if (et == null) return;
        if (!Objects.equals(et.getTenantId(), tenantId)) return;
        if (et.getCheckStatus() == 1) return;
        if (!StaticDict.Order_Return_Status.One.getValue().equals(et.getStatus()) && !StaticDict.Order_Return_Status.Two.getValue().equals(et.getStatus()) && !StaticDict.Order_Return_Status.Three.getValue().equals(et.getStatus()))
            return;
        List<OrderReturnPackDo> packDoList = orderReturnPackDao.selectList(new LambdaQueryWrapper<OrderReturnPackDo>().eq(OrderReturnPackDo::getReturnId, req.getId()));
        Map<Long, OrderReturnPackDo> packCollect = packDoList.stream().collect(Collectors.toMap(OrderReturnPackDo::getId, i -> i));
        for (OrWmsPackScanReq pack : req.getPacks()) {
            if (pack.getReach() == 0) continue;
            if (packCollect.get(pack.getId()) == null) continue;
            LambdaUpdateWrapper<OrderReturnPackDo> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(OrderReturnPackDo::getId, pack.getId());
            updateWrapper.set(packCollect.get(pack.getId()).getReach() == 0, OrderReturnPackDo::getReach, 1);
            updateWrapper.set(packCollect.get(pack.getId()).getReach() == 0, OrderReturnPackDo::getReachTime, new Date());
            updateWrapper.set(OrderReturnPackDo::getLocationId, pack.getLocationId());
            updateWrapper.set(OrderReturnPackDo::getLengthW, pack.getLengthW());
            updateWrapper.set(OrderReturnPackDo::getWidthW, pack.getWidthW());
            updateWrapper.set(OrderReturnPackDo::getHeightW, pack.getHeightW());
            updateWrapper.set(OrderReturnPackDo::getWeightW, pack.getWeightW());
            orderReturnPackService.update(updateWrapper);
            if (packCollect.get(pack.getId()).getReach() == 0)
                operateRecordService.operateAddRecordAndValue("到仓暂存", "", et.getId(), userId, null, OperateTypeEnum.OrderReturn);  //到仓暂存
        }
        //到仓产品  //每次清点都不限制数量，但是如果所有产品都达到了预计数量 就会变成已完成
        for (OrWmsProductScanReq product : req.getProducts()) {
            if (product.getId() == null) {
                if (req.getOperateType() == 0 && product.getThisReceiveGoodQty() == 0 && product.getThisReceiveBadQty() == 0) {
                    throw new BizException(SysConstant.OrderReturn_AddProduct);
                }
                //添加产品
                OrderReturnProductDo productDo = new OrderReturnProductDo();
                productDo.setReturnId(et.getId());
                productDo.setProductId(product.getProductId());
                productDo.setReceiveGoodQty(product.getThisReceiveGoodQty());
                productDo.setReceiveBadQty(product.getThisReceiveBadQty());
                orderReturnProductDao.insert(productDo);
                et.setInventoriedTime(new Date());
            } else {
                if (product.getThisReceiveGoodQty() == 0 && product.getThisReceiveBadQty() == 0) continue;
                orderReturnProductDao.updateReceiveQty(product.getId(), product.getThisReceiveGoodQty(), product.getThisReceiveBadQty());
                et.setInventoriedTime(new Date());//清点时间
            }
        }
        if (StaticDict.Order_Return_Status.One.getValue().equals(et.getStatus())) {
            et.setStatus(StaticDict.Order_Return_Status.Two.getValue());
            //开始处理
            et.setSignBy(userId);
            et.setSignTime(new Date());
        }
        int putCount = orderReturnProductDao.selectCount(new LambdaQueryWrapper<OrderReturnProductDo>().eq(OrderReturnProductDo::getReturnId, req.getId()).last(" and ( receive_good_qty > putaway_good_qty or receive_bad_qty > putaway_bad_qty )"));
        et.setPutStatus(putCount == 0 ? 1 : 2);
        int checkCount = orderReturnProductDao.selectCount(new LambdaQueryWrapper<OrderReturnProductDo>().eq(OrderReturnProductDo::getReturnId, req.getId()).last(" and delivery_qty > (receive_good_qty + receive_bad_qty)"));
        if (checkCount == 0) {
            et.setCheckStatus(1);//说明清点完成
            et.setInventoriedBy(userId);
            et.setInventoriedTime(new Date());
            operateRecordService.operateAddRecordAndValue("清点完成", "", et.getId(), userId, null, OperateTypeEnum.OrderReturn);
        }
        et.setWmsSizeUnit(req.getWmsSizeUnit());
        et.setWarehouseRemark(req.getWarehouseRemark());
        dao.updateById(et);
        List<Long> fileIds = req.getFiles().stream().map(FileRes::getFileId).collect(Collectors.toList());
        fileMoreService.insertFileAndDel(fileIds, et.getId(), StaticDict.File_Type.OrderReturn_Ware.getValue(), userId, null);
    }


    /**
     * 上架初始化
     *
     * @param ids
     * @param warehouseId
     * @return
     */
    @Override
    public List<PutawayInitRes> putawayInit(List<Long> ids, Long warehouseId, Long tenantId) {
        List<PutawayInitRes> resList = new ArrayList<>();
        List<OrderReturnDo> ets = dao.selectList(new LambdaQueryWrapper<OrderReturnDo>().in(OrderReturnDo::getId, ids).eq(OrderReturnDo::getWarehouseId, warehouseId).eq(OrderReturnDo::getTenantId, tenantId));
        if (ets.isEmpty()) return resList;
        Map<Long, List<PackTrackDto>> trackC = orderReturnPackDao.getTracks(ids).stream().collect(Collectors.groupingBy(PackTrackDto::getReturnId));
        Map<Long, List<OrProductPageDto>> productCollect = orderReturnProductDao.list(ids).stream().collect(Collectors.groupingBy(OrProductPageDto::getReturnId));
        Map<Long, Long> skuGoodLocation = redisTemplate.opsForHash().entries(RedisKeyConstants.OrderTurn_LastGoodLocationMap);
        Map<Long, Long> skuBadLocation = redisTemplate.opsForHash().entries(RedisKeyConstants.OrderTurn_LastBadLocationMap);

        Set<Long> locationIds = new HashSet<>();
        for (OrderReturnDo et : ets) {
            if (et.getPutStatus() == 1) continue;
            CompanyDo companyDo = companyDao.selectById(et.getCompanyId());
            if (companyDo == null) continue;
            //待上架产品
            List<OrProductPageDto> productPageList = productCollect.get(et.getId());
            if (productPageList == null) continue;
            for (OrProductPageDto productDto : productPageList) {
                if (productDto.getPutawayGoodQty() < productDto.getReceiveGoodQty()) {
                    Long rackId = skuGoodLocation.get(productDto.getProductId());
                    if (rackId != null) locationIds.add(rackId);
                }
                if (productDto.getPutawayBadQty() < productDto.getReceiveBadQty()) {
                    Long rackId = skuBadLocation.get(productDto.getProductId());
                    if (rackId != null) locationIds.add(rackId);
                }
            }
        }
        Map<Long, String> rackMap = new HashMap<>();
        if (!locationIds.isEmpty()) {
            rackMap = storageLocationDao.selectBatchIds(locationIds).stream().collect(Collectors.toMap(StorageLocationDo::getId, StorageLocationDo::getCode));
        }
        for (OrderReturnDo et : ets) {
            if (et.getPutStatus() == 1) continue;
            CompanyDo companyDo = companyDao.selectById(et.getCompanyId());
            if (companyDo == null) continue;
            PutawayInitRes res = new PutawayInitRes(et.getId(), companyDo.getCompanyName(), companyDo.getCompanyCode(), et.getReturnNo(), et.getReturnType(), et.getStatus(), et.getCreateTime());
            res.setWarehouseId(et.getWarehouseId());
            res.setTrackList(trackC.get(et.getId()));
            //待上架产品
            List<PutawayProductInitRes> products = new ArrayList<>();
            List<OrProductPageDto> productPageList = productCollect.get(et.getId());
            if (productPageList == null) continue;
            for (OrProductPageDto productDto : productPageList) {
                if (productDto.getPutawayGoodQty() < productDto.getReceiveGoodQty()) {
                    //良品可待上架 可上架数量 = 已收数量 - 已上架数量
                    PutawayProductInitRes putawayProductInitRes = new PutawayProductInitRes(0, productDto.getSku(), productDto.getProductId(), productDto.getFnSku(), productDto.getProductName(), productDto.getReceiveGoodQty(), productDto.getPutawayGoodQty(), productDto.getReceiveGoodQty() - productDto.getPutawayGoodQty());
                    this.getRackName(skuGoodLocation, rackMap, products, productDto, putawayProductInitRes);
                }
                if (productDto.getPutawayBadQty() < productDto.getReceiveBadQty()) {
                    PutawayProductInitRes putawayProductInitRes = new PutawayProductInitRes(1, productDto.getSku(), productDto.getProductId(), productDto.getFnSku(), productDto.getProductName(), productDto.getReceiveBadQty(), productDto.getPutawayBadQty(), productDto.getReceiveBadQty() - productDto.getPutawayBadQty());
                    this.getRackName(skuBadLocation, rackMap, products, productDto, putawayProductInitRes);
                }
            }
            if (products.isEmpty()) continue;
            res.setProducts(products);
            resList.add(res);
        }
        return resList;
    }

    private void getRackName(Map<Long, Long> skuLocation, Map<Long, String> rackMap, List<PutawayProductInitRes> products, OrProductPageDto productDto, PutawayProductInitRes putawayProductInitRes) {
        String rackName = rackMap.get(skuLocation.get(productDto.getProductId()));
        if (rackName == null) {
            StorageLocationDo storageLocationDo = storageLocationDao.selectById(skuLocation.get(productDto.getProductId()));
            if (storageLocationDo != null) rackName = storageLocationDo.getCode();
        }
        if (StringUtils.isNotBlank(rackName)) {
            putawayProductInitRes.setLocationName(rackName);
            putawayProductInitRes.setLocationId(skuLocation.get(productDto.getProductId()));
        }
        products.add(putawayProductInitRes);
    }

    @Override
    public List<PutAwayRes> confirmPutaway(List<PutawayInitRes> reqList, Long userId, Long warehouseId, Long tenantId) {
        List<Long> ids = reqList.stream().map(PutawayInitRes::getId).collect(Collectors.toList());
        if (ids.isEmpty()) return null;
        Map<Long, OrderReturnDo> returnMap = dao.selectList(new LambdaQueryWrapper<OrderReturnDo>().in(OrderReturnDo::getId, ids).eq(OrderReturnDo::getTenantId, tenantId))
                .stream().collect(Collectors.toMap(OrderReturnDo::getId, i -> i));
        List<OrProductPageDto> productPageList = orderReturnProductDao.list(ids);
        Map<String, List<OrProductPageDto>> productCollect = productPageList.stream().collect(Collectors.groupingBy(i -> i.getReturnId() + "_" + i.getProductId()));

        List<Long> putIds = new ArrayList<>();
        List<PutAwayRes> resList = new ArrayList<>();
        Map<String, String> goodLoactionMap = new HashMap<>();
        Map<String, String> badLoactionMap = new HashMap<>();
        for (PutawayInitRes putawayInitRes : reqList) {
            OrderReturnDo et = returnMap.get(putawayInitRes.getId()) == null ? null : returnMap.get(putawayInitRes.getId());
            if (et == null || et.getPutStatus() == 1) continue;
            if (!StaticDict.Order_Return_Status.Two.getValue().equals(et.getStatus())) continue;
            //按sku合并先
            Map<String, List<PutawayProductInitRes>> toPutProductMap = putawayInitRes.getProducts().stream().collect(Collectors.groupingBy(i -> i.getProductId() + "-" + i.getProductQuality()));
            for (String productIdAndQuality : toPutProductMap.keySet()) {
//                PutawayProductInitRes productOne = toPutProductMap.get(productId).get(0);
                Long productId = Long.parseLong(productIdAndQuality.split("-")[0]);
                int quality = Integer.parseInt(productIdAndQuality.split("-")[1]);

                List<PutawayProductInitRes> oneSkuPutList = toPutProductMap.get(productIdAndQuality);//单个sku上架汇总
                OrProductPageDto productDo = productCollect.get(et.getId() + "_" + productId) == null ? null : productCollect.get(et.getId() + "_" + productId).get(0);
                if (productDo == null) continue;
                int count = 0;
                if (quality == 0) {
                    //良品
                    if (productDo.getReceiveGoodQty() <= productDo.getPutawayGoodQty()) continue;//良品无可上架数
                    //获取本次总上架数量
                    count = oneSkuPutList.stream().filter(i -> i.getProductQuality() == quality).mapToInt(PutawayProductInitRes::getPutawayQty).sum();
                    if (count > productDo.getReceiveGoodQty() - productDo.getPutawayGoodQty()) continue;
                } else {
                    //次品
                    if (productDo.getReceiveBadQty() <= productDo.getPutawayBadQty()) continue;//良品无可上架数
                    count = oneSkuPutList.stream().filter(i -> i.getProductQuality() == quality).mapToInt(PutawayProductInitRes::getPutawayQty).sum();
                    if (count > productDo.getReceiveBadQty() - productDo.getPutawayBadQty()) continue;
                }
                if (count == 0) continue;
                for (PutawayProductInitRes product : oneSkuPutList) {
                    if (product.getPutawayQty() == 0) continue;
                    if (product.getLocationId() == null) continue;
                    if (product.getProductQuality() == 0) {
                        goodLoactionMap.put(product.getProductId() + "", product.getLocationId() + "");
                    } else {
                        badLoactionMap.put(product.getProductId() + "", product.getLocationId() + "");
                    }
                    //上架到 库位
                    ProductStockDo stockDo = new ProductStockDo(et.getCompanyId(), et.getWarehouseId(), StockOrderTypeEnum.Return.getValue(), et.getId(), product.getProductId(), product.getPutawayQty(), StockTypeEnum.one.getValue(), tenantId);
                    productStockDao.insert(stockDo);
                    ProductStockRackDo rackDo = new ProductStockRackDo(stockDo.getId(), product.getLocationId(), product.getProductQuality(), product.getPutawayQty(), product.getPutawayQty());
                    productStockRackDao.insert(rackDo);
                    if (!putIds.contains(et.getId())) {
                        putIds.add(et.getId());
                    }
                    //库存流水
                    productStockFlowingService.insertProForIn(ProductFlowingInEt.builder().sku(productDo.getSku()).companyId(et.getCompanyId())
                            .warehouseId(et.getWarehouseId()).rackId(product.getLocationId()).stockAttribute(product.getProductQuality())
                            .bookQuantity(product.getPutawayQty()).orderType(StockOrderTypeEnum.Return.getValue()).noteNo(et.getReturnNo())
                            .tenantId(tenantId).type(StockTypeEnum.one.getValue())
                            .build());
                }
                //更新上架数量
                LambdaUpdateWrapper<OrderReturnProductDo> updateWrapper = new LambdaUpdateWrapper<>();
                updateWrapper.eq(OrderReturnProductDo::getId, productDo.getId());
                updateWrapper.setSql(String.format(" %1$s = %1$s + %2$s", quality == 0 ? "putaway_good_qty" : "putaway_bad_qty", count));
                orderReturnProductDao.update(null, updateWrapper);
            }
        }
        if (putIds.isEmpty()) return resList;
        List<OrderReturnDo> finishIds = new ArrayList<>();
        Map<Long, List<OrProductPageDto>> collect = orderReturnProductDao.list(ids).stream().collect(Collectors.groupingBy(OrProductPageDto::getReturnId));
        for (Long returnId : putIds) {
            OrderReturnDo et = returnMap.get(returnId) == null ? null : returnMap.get(returnId);
            if (et == null) continue;
            List<OrProductPageDto> productDo = collect.get(returnId) == null ? null : collect.get(returnId);
            if (productDo == null) continue;
            //能不能清点 能不能上架
            boolean check = false, put = false;
            for (OrProductPageDto productPageDto : productDo) {
                if (et.getCheckStatus() == 2 && productPageDto.getReceiveQty() < productPageDto.getDeliveryQty()) {// 手动完成清点 则不看数量
                    //还能清点
                    check = true;
                }
                if (productPageDto.getPutawayGoodQty() < productPageDto.getReceiveGoodQty() || productPageDto.getPutawayBadQty() < productPageDto.getReceiveBadQty()) {
                    //还能上架
                    put = true;
                }
                if (check && put) break;
            }
            et.setCheckStatus(check ? 2 : 1);
            et.setPutStatus(put ? 2 : 1);
            et.setPutawayTime(new Date());
            if (!check && !put) {
                //上架完成
                et.setStatus(StaticDict.Order_Return_Status.Three.getValue());
                et.setPutawayBy(userId);
//                et.setPutawayTime(new Date());
                operateRecordService.operateAddRecordAndValue("完成上架", "", et.getId(), userId, null, OperateTypeEnum.OrderReturn);
                finishIds.add(et);
            }
            dao.updateById(et);
            resList.add(new PutAwayRes(et.getId(), et.getReturnNo(), et.getStatus()));

        }

        //保存sku 正次品上次上架库位
        Map<String, String> skuGoodLocation = redisTemplate.opsForHash().entries(RedisKeyConstants.OrderTurn_LastGoodLocationMap);
        Map<String, String> skuBadLocation = redisTemplate.opsForHash().entries(RedisKeyConstants.OrderTurn_LastBadLocationMap);
        skuGoodLocation.putAll(goodLoactionMap);
        skuBadLocation.putAll(badLoactionMap);
        redisTemplate.opsForHash().putAll(RedisKeyConstants.OrderTurn_LastGoodLocationMap, skuGoodLocation);
        redisTemplate.opsForHash().putAll(RedisKeyConstants.OrderTurn_LastBadLocationMap, skuBadLocation);

        if (!finishIds.isEmpty()) {
//            List<Long> companyIds = finishIds.stream().map(OrderReturnDo::getCompanyId).distinct().collect(Collectors.toList());
            //获取公司报价方案
            for (OrderReturnDo et : finishIds) {
                //计算退件单属性
                List<OrProductPageDto> orProductPageDtos = collect.get(et.getId());
                CostAddEt costAddEt = new CostAddEt(1, et.getReturnNo(), et.getId(), StaticDict.Cost_ModuleType.First.getValue(), StaticDict.Cost_Input_OrderType.Fourth.getValue(), et.getWarehouseId(), et.getCompanyId(), tenantId, et.getCreateTime());
//                List<OrPackDetailRes> packDetail = this.getPackDetail(et.getId(), et.getSizeUnit(), et.getWmsSizeUnit());
                quotationSchemeService.costAddReturn(costAddEt, orProductPageDtos, et.getTenantId());

            }

        }
        return resList;
    }


    @Override
    public void finishInventory(Long id, Long userId, Long warehouseId, Long tenantId) {
        OrderReturnDo et = dao.selectById(id);
        if (!Objects.equals(et.getWarehouseId(), warehouseId) || !Objects.equals(et.getTenantId(), tenantId)) return;
        if (!StaticDict.Order_Return_Status.Two.getValue().equals(et.getStatus())) return;
        if (et.getCheckStatus() == 1) return;
        List<OrProductPageDto> productPageList = orderReturnProductDao.list(Collections.singletonList(et.getId()));
        int sum = productPageList.stream().mapToInt(ProductQtyDto::getReceiveQty).sum();
        if (sum == 0) return;
        et.setCheckStatus(1);
        et.setInventoriedBy(userId);
        et.setInventoriedTime(new Date());
        if (et.getPutStatus() == 1) {
            //完成清点 没有可上架的 则改成已完成
            et.setStatus(StaticDict.Order_Return_Status.Three.getValue());
            et.setPutawayTime(new Date());
            et.setPutawayBy(userId);
        }
        dao.updateById(et);

        operateRecordService.operateAddRecordAndValue("清点完成", "", et.getId(), userId, null, OperateTypeEnum.OrderReturn);
    }


    @Override
    public OrderReturnImportRes importOrderReturn(MultipartFile file, Long userId, Long warehouseId, Long companyId) {
        if (warehouseId == null) throw new BizException(SysConstant.Pls_Choose_Storage);
        List<OrderReturnImportVo> importVos = null;
        try {
            importVos = ExcelUtils.importExcel(file, 1, 0, OrderReturnImportVo.class);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        if (importVos == null) throw new BizException(SysConstant.No_Data);
        OrderReturnImportRes res = new OrderReturnImportRes();
        List<OrderReturnErrorExportVo> errors = new ArrayList<>();
        Set<String> successId = new HashSet<>();
        Set<String> errorId = new HashSet<>();
        Map<String, List<OrderReturnImportVo>> identCollect = importVos.stream().filter(i -> StringUtils.isNotBlank(i.getIdentificationNo())).collect(Collectors.groupingBy(OrderReturnImportVo::getIdentificationNo));
        Map<String, Long> skuProductId = new HashMap<>();

        importVos.forEach(i -> {
            StringBuilder builder = new StringBuilder();
            if (StringUtils.isBlank(i.getIdentificationNo())) builder.append("标识号不能为空");
            if (StringUtils.isNotBlank(i.getIdentificationNo())) {
                //标识号不为空 则去判断 物流包裹什么的
                List<OrderReturnImportVo> child = identCollect.get(i.getIdentificationNo());
                boolean trackFlag = true, skuFlag = true;
                for (OrderReturnImportVo childVo : child) {
                    if (trackFlag && StringUtils.isNotBlank(childVo.getTrackNo())) trackFlag = false;
                    if (skuFlag && StringUtils.isNotBlank(childVo.getSku())) skuFlag = false;
                    if (!trackFlag && !skuFlag) break;
                }
                if (trackFlag) {
                    if (builder.length() > 0) builder.append(";");
                    builder.append("相同标识号行数据，物流跟踪号不能都为空");
                }
                if (skuFlag) {
                    if (builder.length() > 0) builder.append(";");
                    builder.append("相同标识号行数据，SKU不能都为空");
                }
                if (StringUtils.isNotBlank(i.getSku())) {
                    //判断sku
                    if (skuProductId.get(i.getSku()) == null) {
                        ProductDo productDo = productDao.selectOne(new LambdaQueryWrapper<ProductDo>().eq(ProductDo::getSku, i.getSku())
                                .eq(ProductDo::getCompanyId, companyId));
                        if (productDo == null) {
                            skuProductId.put(i.getSku(), -1L);
                        } else {
                            skuProductId.put(i.getSku(), productDo.getId());
                        }
                    }
                    if (skuProductId.get(i.getSku()) == null || skuProductId.get(i.getSku()) == -1L) {
                        if (builder.length() > 0) builder.append(";");
                        builder.append("sku:").append(i.getSku()).append("不存在");
                    }
                }
                if (StringUtils.isNotBlank(i.getSku()) && (i.getDeliveryQty() == null || i.getDeliveryQty() <= 0)) {
                    if (builder.length() > 0) builder.append(";");
                    builder.append("数量必须大于0");
                }
            }
            if (builder.length() > 0) {
                OrderReturnErrorExportVo errorExportVo = new OrderReturnErrorExportVo();
                BeanUtils.copyProperties(i, errorExportVo);
                errorExportVo.setError(builder.toString());
                errors.add(errorExportVo);
                errorId.add(i.getIdentificationNo());
            } else {
                successId.add(i.getIdentificationNo());
            }
        });
        //成功的去添加
        for (String ident : successId) {
            OrderReturnAddReq addReq = new OrderReturnAddReq();
            List<OrderReturnImportVo> child = identCollect.get(ident);
            addReq.setWarehouseId(warehouseId);
            addReq.setReturnType("平台退件/Platform Returns".equals(child.get(0).getReturnType()) ? 1 : 2);
            addReq.setExpectedDate(child.get(0).getExpectedDate());
            addReq.setRemoveNo(child.get(0).getRemoveNo());
            addReq.setReferOrderNo(child.get(0).getReferOrderNo());
            addReq.setRemark(child.get(0).getRemark());
            addReq.setSizeUnit("英制单位（lb/in）".equals(child.get(0).getSizeUnit()) ? StaticDict.OMP_UnitMeasurement.In.getValue() : StaticDict.OMP_UnitMeasurement.Cm.getValue());

            List<OrPackAddReq> packs = new ArrayList<>();
            Map<String, List<OrderReturnImportVo>> trackC = child.stream().filter(i -> StringUtils.isNotBlank(i.getTrackNo())).collect(Collectors.groupingBy(OrderReturnImportVo::getTrackNo));
            for (String trackNo : trackC.keySet()) {
                OrPackAddReq orPackAddReq = new OrPackAddReq();
                orPackAddReq.setTrackNo(trackNo);
                orPackAddReq.setTips(trackC.get(trackNo).get(0).getPackTips());
                orPackAddReq.setLength(trackC.get(trackNo).get(0).getLength());
                orPackAddReq.setWidth(trackC.get(trackNo).get(0).getWidth());
                orPackAddReq.setHeight(trackC.get(trackNo).get(0).getHeight());
                orPackAddReq.setWeight(trackC.get(trackNo).get(0).getWeight());
                packs.add(orPackAddReq);
            }
            addReq.setPacks(packs);
            Map<String, List<OrderReturnImportVo>> skuC = child.stream().filter(i -> StringUtils.isNotBlank(i.getSku())).collect(Collectors.groupingBy(OrderReturnImportVo::getSku));
            List<OrProductAddReq> products = new ArrayList<>();
            for (String sku : skuC.keySet()) {
                OrProductAddReq orProductAddReq = new OrProductAddReq();
                orProductAddReq.setProductId(skuProductId.get(sku));
                orProductAddReq.setSku(sku);
                orProductAddReq.setDeliveryQty(skuC.get(sku).get(0).getDeliveryQty());
                orProductAddReq.setTips(skuC.get(sku).get(0).getProductTips());
                products.add(orProductAddReq);
            }
            addReq.setProducts(products);
            this.add(addReq, userId, companyId);
        }
        res.setSuccessNum(successId.size());
        res.setFailNum(errorId.size());
        //如果有失败，则生成失败文件
        if (errors.isEmpty()) return res;
        String fileName = "错误_退件单导入" + TimeUtils.getCurrentDateFormat("MMddHHmmss") + ".xlsx";
        ExportParams excelParam = new ExportParams();
        excelParam.setStyle(FarawayExportTitleStyle.class);
        excelParam.setTitleHeight((short) 20);
        try {
            ExcelUtils.exportExcelToSave(errors, OrderReturnErrorExportVo.class, fileName, excelParam, filePathTemp);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        String objectNameTemporary = "";
        if (filePath.startsWith("http")) {
            try {
                objectNameTemporary = AliOss.temporaryFile2(fileName, new File(filePathTemp + fileName));
            } catch (Exception e) {
                e.printStackTrace();
                log.error("导出文件失败" + e.getMessage());
            }
            res.setFailFileUrl(fileUrl + objectNameTemporary);
        } else {
            res.setFailFileUrl(filePathTemp + fileName);
        }
        res.setFileName(fileName);
        return res;
    }


    @Override
    public void printBarCodePdf(PrintReq req, HttpServletResponse response) {
        OrderReturnDo et = dao.selectById(req.getId());
        if (et == null) return;
        //获取退件单 产品以及数量
        List<OrProductPageDto> productPageList = orderReturnProductDao.list(Collections.singletonList(req.getId()));
        List<PrintSkuEt> printSkuEts = new ArrayList<>();
        if (et.getCheckStatus() == 2) {
            for (OrProductPageDto orProductPageDto : productPageList) {
                printSkuEts.add(BeanConvert.INSTANCE.orProductPageDtoDe(orProductPageDto));
            }
            //清点中 按预报数量
        } else {
            //清点完成 按清点数量
            for (OrProductPageDto orProductPageDto : productPageList) {
                printSkuEts.add(BeanConvert.INSTANCE.orProductPageDtoRe(orProductPageDto));
            }
        }
        String name = et.getReturnNo() + "-" + TimeUtils.getCurrentDateFormat("HHmmss");
        //其他纸张类型 一张一个
        BarCodePdfUtils.printManySku(req, printSkuEts, name, response);

    }


    @Override
    public void exportOrderReturn(Map<String, Object> map, HttpServletResponse response) {
        List<OrderReturnWmsExportVo> exportVos = new ArrayList<>();

        List<OrderReturnPageDto> orList = dao.list(map);
        List<List<OrderReturnPageDto>> partition = ListUtil.partition(orList, 5000);
        for (List<OrderReturnPageDto> returnPageList : partition) {
            List<Long> ids = returnPageList.stream().map(OrderReturnPageDto::getId).collect(Collectors.toList());
            //包裹信息
            Map<Long, List<OrPackDetailDto>> packMap = orderReturnPackDao.getTrackDetail(ids).stream().collect(Collectors.groupingBy(OrPackDetailDto::getReturnId));
            //退货产品
            Map<Long, List<OrProductPageDto>> productMap = orderReturnProductDao.list(ids).stream().collect(Collectors.groupingBy(OrProductPageDto::getReturnId));
            for (OrderReturnPageDto returnDto : returnPageList) {
                List<OrPackDetailDto> packs = packMap.get(returnDto.getId());
                List<OrProductPageDto> products = productMap.get(returnDto.getId());
                int packSize = packs == null ? 0 : packs.size();
                int productSize = products == null ? 0 : products.size();
                for (int i = 0; i < Math.max(packSize, productSize); i++) {
                    OrderReturnWmsExportVo exportVo = new OrderReturnWmsExportVo();
                    BeanUtils.copyProperties(returnDto, exportVo);
                    if (products != null) {
                        exportVo.setSkuKind(products.stream().map(OrProductPageDto::getProductId).distinct().count());
                        exportVo.setForecastQty(products.stream().mapToInt(OrProductPageDto::getDeliveryQty).sum());
                    }
                    //包裹信息
                    if (i < packSize) {
                        OrPackDetailDto pack = packs.get(i);
                        exportVo.setTrackNo(pack.getTrackNo());
                        exportVo.setLogisticsCarrierName(pack.getLogisticsCarrierName());
                        exportVo.setReach(pack.getReach());
                        exportVo.setReachTime(pack.getReachTime());
                        exportVo.setLocationCode(pack.getLocationCode());
                        exportVo.setLength(pack.getLength());
                        exportVo.setWidth(pack.getWidth());
                        exportVo.setHeight(pack.getHeight());
                        exportVo.setWeight(pack.getWeight());
                        exportVo.setSizeUnit(StaticDict.OMP_UnitMeasurement.Cm.getValue());
                        exportVo.setLengthW(pack.getLengthW());
                        exportVo.setWidthW(pack.getWidthW());
                        exportVo.setHeightW(pack.getHeightW());
                        exportVo.setWeightW(pack.getWeightW());
                        exportVo.setWmsSizeUnit(StaticDict.OMP_UnitMeasurement.Cm.getValue());
                    } else {
                        exportVo.setSizeUnit(null);
                        exportVo.setWmsSizeUnit(null);

                    }
                    //产品信息
                    if (i < productSize) {
                        OrProductPageDto product = products.get(i);
                        exportVo.setProductSku(product.getSku());
                        exportVo.setProductName(product.getProductName());
                        exportVo.setReceiveGoodQty(product.getReceiveGoodQty());
                        exportVo.setReceiveBadQty(product.getReceiveBadQty());
                        exportVo.setPutawayGoodQty(product.getPutawayGoodQty());
                        exportVo.setPutawayBadQty(product.getPutawayBadQty());
                    } else {
                        exportVo.setReceiveGoodQty(null);
                        exportVo.setReceiveBadQty(null);
                        exportVo.setPutawayGoodQty(null);
                        exportVo.setPutawayBadQty(null);
                    }
                    exportVos.add(exportVo);
                }
            }
        }
        try {
            ExcelUtils.exportExcel(exportVos, OrderReturnWmsExportVo.class, "退件单", new ExportParams(), response);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }

}
